package jenkins

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/cookieY/yee/logger"
	"gorm.io/gorm"
	"helm.sh/helm/v3/pkg/action"
	"log"
	"os"
	"project-info/src/handle/response"
	"project-info/src/lib"
	"project-info/src/lib/helm"
	"project-info/src/model"
	"strconv"
	"time"
)

// AddItemVersion 添加项目版本
func AddItemVersion(c *lib.GinContext) error {
	//1.解析参数
	var itemVersion *model.ItemVersion
	if err := c.Bind(&itemVersion); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	//2. 检验itemVersion 是否存在
	var dbItemVersions []model.ItemVersion
	if err := model.DB().Where("item_id = ?", itemVersion.ItemId).Find(&dbItemVersions).Error; err != nil && err != gorm.ErrRecordNotFound {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "查询失败")
	}

	var item *model.Item
	if err := model.DB().Where("id = ?", itemVersion.ItemId).First(&item).Error; err != nil && err != gorm.ErrRecordNotFound {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "查询失败")
	}
	// node项目只能有一个版本,当查询出的记录大于1或者等于1但是id不等于当前id时，返回错误
	if item.DeployType == "node" && (len(dbItemVersions) > 1 || (len(dbItemVersions) == 1 && dbItemVersions[0].Id != itemVersion.Id)) {
		return response.JsonFail(c, "node项目只能有一个版本")
	}

	//1.判断版本是否存在
	//2.判断相同id的version是否一致
	for _, version := range dbItemVersions {
		if version.Id != itemVersion.Id && version.Version == itemVersion.Version {
			return response.JsonFail(c, "版本已存在")
		} else if version.Id == itemVersion.Id && version.Version != itemVersion.Version {
			return response.JsonFail(c, "版本名称不可修改")
		}
	}
	syncJenkinsChan := make(chan bool)
	defer close(syncJenkinsChan)
	go syncJenkins(itemVersion, syncJenkinsChan)

	//3.保存数据
	itemVersion.Time = time.Now()
	if itemVersion.Id != 0 {
		model.DB().Save(itemVersion)
	} else {
		model.DB().Create(itemVersion)
	}

	//3.判断item_id 是否有其他版本，如果没有，则生成默认的flow_control
	if len(dbItemVersions) == 0 {
		err := createDefaultFlowCtrol(c, item, itemVersion)
		if err != nil {
			c.Logger().Error(err.Error())
			return response.JsonFail(c, "创建默认流量控制失败")
		}
	}
	syncJenkinsChan <- true
	return response.JsonOk(c, itemVersion, "ok")
}

// UpdateItemVersion 更新项目版本
func UpdateItemVersion(c *lib.GinContext) error {
	//1.解析参数
	var itemVersion *model.ItemVersion
	if err := c.Bind(&itemVersion); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	//2.保存数据
	model.DB().Save(itemVersion)
	return response.JsonOk(c, itemVersion, "ok")
}

// DeleteItemVersion 删除项目版本
func DeleteItemVersion(c *lib.GinContext) error {
	//1.解析参数
	var itemVersion *model.ItemVersion
	if err := c.Bind(&itemVersion); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	//2.查询流量控制
	var flowControl model.FlowControl
	result := model.DB().Where("item_id = ?", itemVersion.ItemId).First(&flowControl)
	if result.Error != nil && result.Error != gorm.ErrRecordNotFound {
		c.Logger().Error(result.Error.Error())
		return response.JsonFail(c, "未查询到流量控制数据")
	}

	// 总的版本数
	var totalVersion int64
	err := model.DB().Model(&model.ItemVersion{}).Where("item_id = ?", itemVersion.ItemId).Count(&totalVersion).Error
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "查询总版本数失败")
	}

	var defaultFlowControl []map[string]interface{}
	err = json.Unmarshal(flowControl.DefaultFlow, &defaultFlowControl)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "流量控制数据解析失败")
	}

	var advancedFlowControl []map[string]interface{}
	err = json.Unmarshal(flowControl.AdvancedFlow, &advancedFlowControl)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "流量控制数据解析失败")
	}

	versions := make(map[string]bool)
	for _, m := range defaultFlowControl {
		versions[m["version"].(string)] = true
	}

	for _, m := range advancedFlowControl {
		versions[m["version"].(string)] = true
	}

	if totalVersion == 1 && versions[itemVersion.Version] {
		go processDeleteFlowControl(c, flowControl)
	} else if totalVersion > 1 && versions[itemVersion.Version] {
		return response.JsonFail(c, "当前版本已经在流量控制中使用，清除流量控制后再删除")
	}

	//2.删除数据
	model.DB().Where("id = ?", itemVersion.Id).Delete(&model.ItemVersion{})

	//3.删除jenkins job 与 k8s 中的helm资源
	go pruneResource(c, itemVersion)

	return response.JsonOk(c, itemVersion, "ok")
}

// pruneResource 删除jenkins job 与 k8s 中的资源
func pruneResource(c *lib.GinContext, itemVersion *model.ItemVersion) error {
	var item *model.Item
	model.DB().Where("id = ?", itemVersion.ItemId).First(&item)

	_, err := model.JenkinsConnection.DeleteJob(context.TODO(), concatJenkinsDeleteJobName(itemVersion))
	if err != nil {
		logger.DefaultLogger.Error("删除jenkins job错误" + err.Error())
		return err
	}

	err = deleteHelmResource(c, item, itemVersion)
	if err != nil {
		logger.DefaultLogger.Error("删除helm 资源错误" + err.Error())
		return err
	}
	return nil
}

// deleteHelmResource 删除helm 资源
func deleteHelmResource(c *lib.GinContext, item *model.Item, itemVersion *model.ItemVersion) error {
	k8sCluster, err := resourceService.GetK8sConfig(c, item)
	if err != nil {
		return err
	}

	actionConfig := new(action.Configuration)
	restClientGetter := helm.NewRESTClientGetter(item.Namespace, k8sCluster.Config)
	if err := actionConfig.Init(restClientGetter, item.Namespace, os.Getenv("HELM_DRIVER"), log.Printf); err != nil {
		return err
	}

	// 创建 uninstall action 客户端
	uninstallClient := action.NewUninstall(actionConfig)
	_, err = uninstallClient.Run(fmt.Sprintf("%s-%s", item.AppName, itemVersion.Version))
	if err != nil {
		logger.DefaultLogger.Error(err.Error())
		return err
	}
	return nil
}

// GetItemVersionList 获取项目版本列表
func GetItemVersionList(c *lib.GinContext) error {
	//1.解析参数
	itemIdP := c.QueryParam("item_id")
	itemId, err := strconv.ParseUint(itemIdP, 10, 0)
	if err != nil {
		return response.JsonFail(c, "参数解析错误")
	}
	//2.查询数据
	var itemVersions []model.ItemVersion
	result := model.DB().Where("item_id = ?", itemId).Find(&itemVersions)
	if result.Error != nil && result.Error != gorm.ErrRecordNotFound {
		return response.JsonFail(c, "查询失败")
	}
	return response.JsonOk(c, itemVersions, "ok")
}

// createDefaultFlowCtrol 创建默认的流量控制
func createDefaultFlowCtrol(c *lib.GinContext, item *model.Item, itemVersion *model.ItemVersion) error {
	defaultFlow := []map[string]interface{}{
		{"version": itemVersion.Version, "percent": 100},
	}
	marshal, err := json.Marshal(defaultFlow)
	if err != nil {
		return err
	}

	flowControl := &model.FlowControl{
		ItemId:       itemVersion.ItemId,
		DefaultFlow:  marshal,
		AdvancedFlow: []byte("[]"),
	}
	return processUpdateFlowControl(c, flowControl, item, itemVersion)
}

// SyncJenkins 同步pipeline到jenkins
func syncJenkins(itemVersion *model.ItemVersion, jenkinsChan chan bool) {
	ctx := context.Background()
	select {
	case <-jenkinsChan:
		//0.配置
		templateJobName := "template"
		//1.查找模板job
		config, err := lib.GetJenkinsJobConfig(model.JenkinsConnection, templateJobName, parentFolder)
		if err != nil {
			logger.DefaultLogger.Error("获取模板job配置失败" + err.Error())
		}
		//2.同步到jenkins,根据pipeline id作为job name,如果不存在则创建
		model.JenkinsConnection.CreateJobInFolder(ctx, config, concatJenkinsJobName(itemVersion), parentFolder...)
	}
}
